using FlickrNet;
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using WindowsLive.Writer.Api;

namespace TrailImage
{
	public enum ImageSize {
		Square75,
		Square150,
		Thumbnail100,
		Small240,
		Small320,
		Medium500,
		Medium640,
		Medium800,
		Large1024,
		Large2048,
		Original
	}
	/// <summary>
	/// Extension methods
	/// </summary>
    public static class Extensions
	{
		#region Controls

		public static bool? AllSelected(this ListView listView)
		{
			int selectCount = listView.SelectedItems.Count;
			if (selectCount == listView.Items.Count) {
				return true;
			} else if (selectCount == 0) {
				return false;
			} else {
				return null;
			}
		}

		#endregion

		#region Form

		public static void SetSelected(this ComboBox list, object value)
		{
			if (list.Items.Count == 0 || value == null) { return; }
			var property = list.Items[0].GetType().GetProperty(list.ValueMember);
			for (int i = 0; i < list.Items.Count; i++)
			{
				if (property.GetValue(list.Items[i], null).Equals(value))
				{
					list.SelectedIndex = i;
					break;
				}
			}
		}

		/// <summary>
		/// Begin an worker process, cancelling existing threads as necessary
		/// </summary>
		public static void DoWork(this Form form, BackgroundWorker worker)
		{
			if (worker.IsBusy) { worker.CancelAsync(); }
			while (worker.CancellationPending) { Application.DoEvents(); }
			worker.RunWorkerAsync();
		}

		/// <summary>
		/// Ensure operation is run in the UI thread
		/// </summary>
		public static void RunInMainThread(this Form form, Action fn)
		{
			if (fn != null)
			{
				if (form.InvokeRequired) { form.Invoke(fn); } else { fn(); }
			}
		}

		/// <summary>
		/// Run operation in UI thread to return a value
		/// </summary>
		public static T ValueFromMainThread<T>(this Form form, Func<T> fn)
		{
			if (form.InvokeRequired) { return (T)form.Invoke(fn); } else { return fn(); }
		}

		#endregion

		public static T ToEnum<T>(this int x) { return (T)(object)x; }

		public static void ReportProgress(this BackgroundWorker worker, int current, int total)
		{
			worker.ReportProgress((int)(100 * ((double)current / total)));
		}
		public static int NumbersOnly(this string s)
		{
			return int.Parse(Regex.Replace(s, @"\D", ""));
		}
		/// <summary>
		/// Return numeric portion of enumeration name
		/// </summary>
		public static int NumbersOnly(this Enum e) { return e.ToString().NumbersOnly(); }

		#region Flickr

		/// <summary>
		/// Build function that will select the URL for a given image size
		/// </summary>
		/// http://www.flickr.com/services/api/misc.urls.html
		/// The letter suffixes are as follows:
		/// s small square 75x75
		/// t	thumbnail, 100 on longest side
		///	m	small, 240 on longest side
		///	-	medium, 500 on longest side
		///	z	medium 640, 640 on longest side
		///	b	large, 1024 on longest side*
		///	o	original image, either a jpg, gif or png, depending on source format
		///	Before May 25th 2010 large photos only exist for very large original images.
		/// Note: Original photos behave a little differently. They have their own secret
		/// (called originalsecret in responses) and a variable file extension (called
		/// originalformat in responses). These values are returned via the API only when
		/// the caller has permission to view the original size (based on a user preference
		/// and various other criteria). The values are returned by the flickr.photos.getInfo
		/// method and by any method that returns a list of photos and allows an extras
		/// parameter (with a value of original_format), such as flickr.photos.search. The
		/// flickr.photos.getSizes method, as always, will return the full original URL where
		/// permissions allow.
		/// </remarks>
		public static Func<Photo, string> PhotoUrlFunc(ImageSize imgsize)
		{
			switch (imgsize) 
			{
				case ImageSize.Square75: return new Func<Photo, string>(p => p.SquareThumbnailUrl);
				case ImageSize.Square150: return new Func<Photo, string>(p => p.LargeSquareThumbnailUrl);
				case ImageSize.Thumbnail100: return new Func<Photo, string>(p => p.ThumbnailUrl);
				case ImageSize.Small240: return new Func<Photo, string>(p => p.SmallUrl);
				case ImageSize.Small320: return new Func<Photo, string>(p => p.Small320Url);
				case ImageSize.Medium500: return new Func<Photo, string>(p => p.MediumUrl);
				case ImageSize.Medium640: return new Func<Photo, string>(p => p.Medium640Url);
				case ImageSize.Medium800: return new Func<Photo, string>(p => p.Medium640Url);
				case ImageSize.Large1024: return new Func<Photo, string>(p => p.LargeUrl);
				case ImageSize.Large2048: return new Func<Photo, string>(p => p.LargeUrl);
				case ImageSize.Original: return new Func<Photo, string>(p => p.OriginalUrl);
			}
			return null;
		}

		public static string Name(this Photo p)
		{
			return (string.IsNullOrEmpty(p.Title)) ? p.PhotoId : p.Title;
		}

		/// <summary>
		/// Key to use when grouping photos in a ListView control
		/// </summary>
		public static string GroupKey(this FlickrNet.Photo p)
		{
			return p.DateTaken.ToLongDateString();
		}

		/// <summary>
		/// Set token in plugin and profile
		/// </summary>
		public static void SetAccessToken(this FlickrNet.Flickr f, OAuthAccessToken token)
		{
			f.OAuthAccessToken = token.Token;
			f.OAuthAccessTokenSecret = token.TokenSecret;
			Profile.Current.AccessToken = token;
		}

		/// <summary>
		/// Get Flickr URL for given image size
		/// </summary>
		public static string UrlForSize(this FlickrNet.Photo p, ImageSize size)
		{
			return PhotoUrlFunc(size).Invoke(p);
		}

		/// <summary>
		/// Get byte stream for given image
		/// </summary>
		public static MemoryStream ToStream(this FlickrNet.Photo p, ImageSize size)
		{
			var stream = new MemoryStream();
			var http = new PluginHttpRequest(p.UrlForSize(size)) {
				AllowAutoRedirect = true,
				CacheLevel = HttpRequestCacheLevel.BypassCache
			};
			using (Stream httpStream = http.GetResponse()) {
				byte[] buffer = new byte[0x1000];
				int count;
				while ((count = httpStream.Read(buffer, 0, buffer.Length)) > 0)
				{
					stream.Write(buffer, 0, count);
				}
			}
			return stream;
		}

		/// <summary>
		/// Create image object from photo reference
		/// </summary>
		public static Image ToImage(this FlickrNet.Photo p, ImageSize size)
		{
			return Image.FromStream(p.ToStream(size));
		}

		#endregion

		#region DateTime

		public static DateTime StartOfDay(this DateTime dt) {
			return new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0);
		}

		#endregion

	}
}
